package edu.tec.mty.core.modules;

import java.util.ArrayList;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.Condition;
import java.util.regex.Pattern;

import edu.tec.mty.core.connection.*;

public class Game {
	
	private static ArrayList<String> playModes = new ArrayList<String>();
	private String playMode = "before_kick_off";
	public static long GAME_TIME = 0;
	public static long SIMULATION_TIME = 0;
	private boolean logical = false;
	private Dispatcher dispatcher;
	private final Lock lock = new ReentrantLock();
	private final Condition newCycle = lock.newCondition();
	private Self player;
	private World world;
	
	public Game(Dispatcher dispatcher, Self player, World world) {
		Game.playModes.add("before_kick_off");
		Game.playModes.add("corner_kick_l");
		Game.playModes.add("corner_kick_r");
		Game.playModes.add("drop_ball");
		Game.playModes.add("free_kick_l");
		Game.playModes.add("free_kick_r");
		Game.playModes.add("goal_kick_l");
		Game.playModes.add("goal_kick_r");
		Game.playModes.add("goal_l");
		Game.playModes.add("goal_r");
		Game.playModes.add("half_time");
		Game.playModes.add("kick_in_l");
		Game.playModes.add("kick_in_r");
		Game.playModes.add("kick_off_l");
		Game.playModes.add("kick_off_r");
		Game.playModes.add("offside_l");
		Game.playModes.add("offside_r");
		Game.playModes.add("play_on");
		Game.playModes.add("time_extended");
		Game.playModes.add("time_over");
		this.dispatcher = dispatcher;
		this.player = player;
		this.world = world;
	}

	public String getPlayMode() {
		return this.playMode;
	}
	
	public void notifyPlayMode(String playMode) {
		if (Pattern.matches("(goal_left_\\d+|goal_right_\\d+)", playMode)) {
			int lastIndex = playMode.lastIndexOf('_');
			playMode = playMode.substring(0, lastIndex);
		}
		if (Game.playModes.contains(playMode)) {
			this.playMode = playMode;
		}
	}
	
	public long getPlayTime() {
		return Game.GAME_TIME;
	}
	
	public long getGlobalTime() {
		return Game.SIMULATION_TIME;
	}
	
	public long getStep() {
		try {
			this.lock.lock();
			while(!this.logical) {
				this.newCycle.await();
			}
			this.lock.unlock();
		} catch (Exception e) {
			System.err.println(e);
		}
		this.logical = false;
		return Game.SIMULATION_TIME;
	}
	
	public void turnOnLogicalTime() {
		this.lock.lock();
		this.logical = true;
		this.newCycle.signal();
		this.lock.unlock();
	}
	
	public void turnOffLogicalTime() {
		this.lock.lock();
		this.logical = false;
		this.lock.unlock();
	}
	
	public void updateTime(long time) {
		this.lock.lock();
		this.logical = true;
		Game.GAME_TIME = time;
		Game.SIMULATION_TIME++;
		this.dispatcher.sendCommand();
		this.newCycle.signal();
		this.lock.unlock();
		this.player.setGlobalTime(SIMULATION_TIME);
		this.world.setGlobalTime(SIMULATION_TIME);
	}
}
